/*
 * Author: Alberto De Pena
 * Applied Algorithms
 * ghost.cpp
*/
#include <iostream>
#include <fstream>
#include <queue>
#include <vector>
using namespace std;

struct Ghost
{
    double x;
    double y;
};

struct Ghostbuster
{
    double x;
    double y;
};

struct Line
{
    double slope;
    double b;
    Ghost ghost;
    Ghostbuster ghostbuster;

    bool operator < (const Line other) const

    {
        if (ghostbuster.x > other.ghostbuster.x)
            return true;
        else if (ghostbuster.x == other.ghostbuster.x)
        {
            if(ghostbuster.y > other.ghostbuster.y)
                return true;
        }
        return false;
    }

    double eval (double x)
    {
        return slope*x + b;
    }
};

void DeterminePairs(vector<Ghost> Ghosts, vector<Ghostbuster> Ghostbusters, priority_queue<Line> &Pairs)
{
    Line beam;
    vector<Ghost> topHalfGhost, bottomHalfGhost;
    vector<Ghostbuster> topHalfGhostbuster, bottomHalfGhostbuster;

    if(Ghostbusters.size() == 1)
    {
        beam.slope = (Ghostbusters[0].y - Ghosts[0].y) / (Ghostbusters[0].x - Ghosts[0].x);
        beam.b = Ghostbusters[0].y - beam.slope * Ghostbusters[0].x;
        beam.ghost = Ghosts[0];
        beam.ghostbuster = Ghostbusters[0];

        Pairs.push(beam);
    }
    else
    {
        for(unsigned int i = 0; i < Ghostbusters.size(); i++)
        {
            for(unsigned int j = 0; j < Ghosts.size(); j++)
            {
                beam.slope = (Ghostbusters[i].y - Ghosts[j].y) / (Ghostbusters[i].x - Ghosts[j].x);
                beam.b = Ghostbusters[i].y - beam.slope * Ghostbusters[i].x;
                beam.ghost = Ghosts[j];
                beam.ghostbuster = Ghostbusters[i];

                //check if the rest of the ghostbusters split evenly above and below the beam
                for(unsigned int k = 0; k < Ghostbusters.size(); k++)
                {
                    //if not itself
                    if(k != i)
                    {
                        if(Ghostbusters[k].y > beam.eval(Ghostbusters[k].x))
                            topHalfGhostbuster.push_back(Ghostbusters[k]);
                        else if(Ghostbusters[k].y < beam.eval(Ghostbusters[k].x))
                            bottomHalfGhostbuster.push_back(Ghostbusters[k]);
                    }
                }

                //if it is REALLY cut in half, go on to ghosts
                if(topHalfGhostbuster.size() + bottomHalfGhostbuster.size() == Ghostbusters.size() - 1)
                {
                    //check if the rest of the ghosts split evenly above and below the beam
                    for(unsigned int k = 0; k < Ghosts.size(); k++)
                    {
                        //if not itself
                        if(k != j)
                        {
                            if(Ghosts[k].y > beam.eval(Ghosts[k].x))
                                topHalfGhost.push_back(Ghosts[k]);
                            else if(Ghosts[k].y < beam.eval(Ghosts[k].x))
                                bottomHalfGhost.push_back(Ghosts[k]);
                        }
                    }

                    //if it is REALLY cut in half
                    if(bottomHalfGhost.size() == bottomHalfGhostbuster.size() && topHalfGhost.size() == topHalfGhostbuster.size())
                    {
                        Pairs.push(beam);

                        DeterminePairs(bottomHalfGhost, bottomHalfGhostbuster, Pairs);
                        DeterminePairs(topHalfGhost, topHalfGhostbuster, Pairs);
                        return;
                    }
                }

                topHalfGhost.clear();
                bottomHalfGhost.clear();
                topHalfGhostbuster.clear();
                bottomHalfGhostbuster.clear();
            }
        }
    }
}

void main()
{
    ifstream fin;
    ofstream fout;

	fin.open("ghosts.in");
    fout.open("ghosts.out");

    int n, setNum = 1;
    Ghost ghost;
    Ghostbuster ghostbuster;
    vector<Ghost> Ghosts;
    vector<Ghostbuster> Ghostbusters;
    priority_queue<Line> Pairs;
    Line line;

    fin >> n;

    while(n > 0)
    {
        fout << "Data Set #" << setNum << endl;
        setNum++;

        //get ghostbuster points
        for(int i = 0; i < n; i++)
        {
            fin >> ghostbuster.x >> ghostbuster.y;
            Ghostbusters.push_back(ghostbuster);
        }

        //get ghost points
        for(int i = 0; i < n; i++)
        {
            fin >> ghost.x >> ghost.y;
            Ghosts.push_back(ghost);
        }

        DeterminePairs(Ghosts, Ghostbusters, Pairs);

        //output pairs
        while(!Pairs.empty())
        {
            line = Pairs.top();
            fout.precision(1);
            fout << fixed;
            fout << "(" << line.ghostbuster.x << "," << line.ghostbuster.y << ")->("
                 << line.ghost.x << "," << line.ghost.y << ")" << endl;
            Pairs.pop();
        }

        Ghostbusters.clear();
        Ghosts.clear();

        fin >> n;
    }

    fin.close();
    fout.close();
}

